<?php
/**
 * Short description for file
 *
 * Long description for file (if any)...
 *
 * LICENSE: Eclipse Public License 1.0
 *
 * @category   Metis
 * @package    Metis_Controller
 * @copyright  2009 Darryl Patterson <widgetapps@gmail.com>
 * @license    http://metis.widgetapps.ca/license   Eclipse Public License 1.0
 * @version    $Id:$
 * @link       http://code.google.com/p/widgetapps-metis/
*/

abstract class Metis_Controller_Action extends Zend_Controller_Action
{
    private $languageLabels;
    protected $auth;
    protected $acl;
	
	function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array())
	{
	    parent::__construct($request, $response, $invokeArgs);
	    $this->auth        = Zend_Auth::getInstance();
	    $this->acl         = new Zend_Acl();
        
        if ($this->auth->hasIdentity()){
            $this->view->role        = $this->auth->getIdentity()->role;
            $this->view->hasIdentity = true;
            $this->view->userId      = $this->auth->getIdentity()->userId;
        } else {
            $this->view->role        = 'guest';
            $this->view->hasIdentity = false;
        }
	    
    	$this->_helper->layout->setLayout('default');
    	$this->languageLabels = array();
    	$this->loadLabels();
    	$this->view->setLanguageLabels($this->languageLabels);
    	$this->setupAcl();
	}

    public function init()
    {
        $this->_redirector = $this->_helper->getHelper('Redirector');
    }
	
	protected function getLabel($key)
	{
	    if (isset($this->languageLabels[$key])){
	        return $this->languageLabels[$key];
	    }
	    
	    return '';
	}
    
    protected function canView()
    {
        return $this->authenticateAction('view');
    }
    
    protected function canAdd()
    {
        return $this->authenticateAction('add');
    }
    
    protected function canEdit()
    {
        return $this->authenticateAction('edit');
    }
    
    protected function canDelete()
    {
        return $this->authenticateAction('delete');
    }
    
    protected function failedLogin()
    {
        $failedLogin = new Zend_Session_Namespace('failedLogin');
        $failedLogin->setExpirationHops(3);
        $failedLogin->redirect = $_SERVER['REQUEST_URI'];
        $this->_redirect($this->config->failed_login_redirect);
    }
	
    // TODO: Add in exception handling.
	function setupAcl()
	{
	    if ($this->acl !== null){
	        return;
	    }
	    
	    $this->acl = new Zend_Acl();
	    
	    $aclPath = APPLICATION_PATH . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'acl.xml';
	                        
	    if (!file_exists($aclPath)){
	        throw new Metis_Exception('Cannot find ACL file: [' . $aclPath . ']');
	    }
	    
	    $acl_dom = new DOMDocument();
	    $acl_dom->load($aclPath);
	    
	    if ($this->view->getEncoding() != $acl_dom->encoding){
	        throw new Metis_Exception('Error loading ACL file [' . $aclPath . ']: XML encoding did not match. This application requires ' . $this->view->getEncoding());
	    }
	    
	    $acl_xml = simplexml_import_dom($acl_dom);
	    
	    // Load the roles
	    foreach ($acl_xml->roles->role as $role){
	        $this->acl->addRole(new Zend_Acl_Role((string)$role['name']));
	    }
	    
	    // Load the resources
	    foreach ($acl_xml->resources->resource as $resource){
	        try {
	            $this->acl->add(new Zend_Acl_Resource((string)$resource['name']));
	        } catch (Exception $e) {}
	    }
	    
	    // Load the rights
	    // TODO: Need to account for null resource, if no resources are defined.
	    foreach ($acl_xml->rights->right as $right){
	        $rightsArray = array();
	        foreach ($right->children() as $child){
	            $rightsArray[] = $child->getName();
	        }
	        
	        switch ((string)$right['type']){
	            case 'allow':
	                $this->acl->allow((string)$right['role'], (string)$right['resource'], $rightsArray);
	                break;
	            case 'deny':
	                $this->acl->deny((string)$right['role'], (string)$right['resource'], $rightsArray);
	                break;
	        }
	    }
	}
    
    protected function authenticateAction($privilege)
    {
        return $this->acl->isAllowed($this->auth->getIdentity()->role, $this->moduleName, $privilege);
    }
    
    protected function getLanguage()
    {
    	$session_env = new Zend_Session_Namespace('env');
        if (isset($session_env->language)){
        	return $session_env->language;
        }
        
    	$resources = $this->getInvokeArg('bootstrap')->getOption('resources');
    	if (isset($resources['view']['language'])){
    		return $resources['view']['language'];
    	}
    	
    	return 'en';
    }
	
	private function loadLabels()
	{
	    $globalLabelsPath = APPLICATION_PATH . 
	                        DIRECTORY_SEPARATOR . 'localization' . DIRECTORY_SEPARATOR . 
	                        $this->getLanguage() . '.xml';
	    $this->loadLabelFile($globalLabelsPath);
	    
	    $moduleLabelPath  = APPLICATION_PATH . 
	                        DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR .
	                        $this->getRequest()->getModuleName() . DIRECTORY_SEPARATOR .
	                        'localization' . DIRECTORY_SEPARATOR . $this->getLanguage() .
	                        '.xml';
	    $this->loadLabelFile($moduleLabelPath);
	}
	
	private function loadLabelFile($path)
	{
	    if (!file_exists($path)){
	        throw new Metis_Exception('Cannot find language file: [' . $path . ']');
	    }
	    
	    $language_dom = new DOMDocument();
	    $language_dom->load($path);
	    if ($this->view->getEncoding() != $language_dom->encoding){
	        throw new Metis_Exception('Error loading language file [' . $path . ']: XML encoding did not match.');
	    }
	    
	    $language_xml = simplexml_import_dom($language_dom);
	    foreach ($language_xml->label as $label){
	        $key   = (string)$label['key'];
	        $value = (string)$label;
	        $this->languageLabels[trim($key)] = trim($value);
	    }
	}
}
